﻿using System;
using System.Linq;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using YSGetLatest.Commands;
using YSGetLatest.DataObjects;

namespace YSGetLatest.ViewModels
{
	/// <summary>
	/// View model for main window
	/// </summary>
	public class MainWindowViewModel
	{
		#region Fields

		private readonly Window window_;
		private readonly Projects projects_ = new Projects();
		private readonly IYSCommand quitCommand_ = new Command();
		private readonly IYSCommand addProjectCommand_ = new Command();
		private readonly IYSCommand deleteProjectCommand_ = new Command();
		private readonly IYSCommand openProjectCommand_ = new Command();
		private readonly IYSCommand optionsCommand_ = new Command();
		private readonly ListBox projectListBox_;
		private readonly EnablementManager enablementManager_;

		private Project selectedProject_;
		#endregion

		#region Properties

		/// <summary>
		/// Gets the Projects.
		/// </summary>
		public Projects Projects
		{
			get
			{
				return projects_;
			}
		}

		/// <summary>
		/// Gets the Quit Command.
		/// </summary>
		public IYSCommand QuitCommand
		{
			get
			{
				return quitCommand_;
			}
		}

		/// <summary>
		/// Gets the AddProject Command
		/// </summary>
		public IYSCommand AddProjectCommand
		{
			get
			{
				return addProjectCommand_;
			}
		}

		/// <summary>
		/// Gets the Delete Command
		/// </summary>
		public IYSCommand DeleteProjectCommand
		{
			get
			{
				return deleteProjectCommand_;
			}
		}

		/// <summary>
		/// Gets the Open Command
		/// </summary>
		public IYSCommand OpenProjectCommand
		{
			get
			{
				return openProjectCommand_;
			}
		}

		/// <summary>
		/// Gets the Options Command
		/// </summary>
		public IYSCommand OptionsCommand
		{
			get
			{
				return optionsCommand_;
			}
		}
		#endregion

		#region Constructors

		/// <summary>
		/// Initializes a new instrance of the MainWindowViewModel.
		/// </summary>
		/// <param name="window">Reference to window.</param>
		/// <param name="projectListBox">Reference to list with projects.</param>
		public MainWindowViewModel(Window window, ListBox projectListBox)
		{
			if (window == null)
			{
				throw new ArgumentNullException("window");
			}
			if (projectListBox == null)
			{
				throw new ArgumentNullException("projectListBox");
			}

			window_ = window;
			window_.Closing += OnClosing;
			projectListBox_ = projectListBox;

			projects_.LoadProjects();

			projectListBox_.SelectionChanged += OnProjectListBoxSelectionChanged;
			quitCommand_.OnExecute += OnQuit;
			addProjectCommand_.OnExecute += OnAddProject;
			deleteProjectCommand_.OnExecute += OnDeleteProject;
			openProjectCommand_.OnExecute += OnOpenProject;
			optionsCommand_.OnExecute += OnOptions;

			enablementManager_ = new EnablementManager();

			enablementManager_.AddCommand(quitCommand_, ExecutionState.NoRunning,
				new ListState[] { ListState.All }, null,
				new SelectionState[] { SelectionState.All }, null);
			enablementManager_.AddCommand(addProjectCommand_, ExecutionState.NoRunning,
				new ListState[] { ListState.All }, null,
				new SelectionState[] { SelectionState.All }, null);
			enablementManager_.AddCommand(deleteProjectCommand_, ExecutionState.NoRunning,
				new ListState[] { ListState.NoEmpty }, new ListState[] { ListState.Empty },
				new SelectionState[] { SelectionState.OneItemSelected }, new SelectionState[] { SelectionState.ManyItemsSelected, SelectionState.NoOneItemSelected });
			enablementManager_.AddCommand(openProjectCommand_, ExecutionState.NoRunning,
				new ListState[] { ListState.NoEmpty }, new ListState[] { ListState.Empty },
				new SelectionState[] { SelectionState.OneItemSelected }, new SelectionState[] { SelectionState.ManyItemsSelected, SelectionState.NoOneItemSelected });
			enablementManager_.AddCommand(optionsCommand_, ExecutionState.NoRunning,
				new ListState[] { ListState.All }, null,
				new SelectionState[] { SelectionState.All }, null);

			enablementManager_.ListState = ListState.Empty;
			enablementManager_.SelectionState = SelectionState.NoOneItemSelected;
			enablementManager_.ExecutionState = ExecutionState.NoRunning;
		}
		#endregion

		#region Methods

		private void OnClosing(object sender, CancelEventArgs e)
		{
			projects_.SaveProjects();
		}

		private void OnProjectListBoxSelectionChanged(object sender, SelectionChangedEventArgs e)
		{

			selectedProject_ = e.AddedItems.Count == 1 ? e.AddedItems[0] as Project : null;

			enablementManager_.ListState = Projects.ProjectList.Count == 0 ? ListState.Empty : ListState.NoEmpty;
			var selectedItemsCount = Projects.ProjectList.Where(p => p.IsSelected).Count();

			if (selectedItemsCount == 0)
			{
				enablementManager_.SelectionState = SelectionState.NoOneItemSelected;
			}
			else if (selectedItemsCount == 1)
			{
				enablementManager_.SelectionState = SelectionState.OneItemSelected;
			}
			else
			{
				enablementManager_.SelectionState = SelectionState.ManyItemsSelected;
			}
		}

		private void OnQuit()
		{
			window_.Close();
		}

		private void OnAddProject()
		{
			var project = new Project();

			var dlg = new ProjectWindow(project)
			{
				Owner = window_
			};
			bool? result = dlg.ShowDialog();

			if (!(result.HasValue && result.Value))
				return;

			Projects.ProjectList.Add(project);
			project.IsSelected = true;
			Projects.SaveProjects();
		}

		private void OnDeleteProject()
		{
			if (selectedProject_ == null
				|| MessageBox.Show(string.Format("Are you sure delete {0} project?",
				selectedProject_.Name), "Delete Folder", MessageBoxButton.OKCancel, MessageBoxImage.Question) != MessageBoxResult.OK)
				return;

			Projects.ProjectList.Remove(selectedProject_);
			Projects.SaveProjects();
		}

		private void OnOpenProject()
		{
			if (selectedProject_ == null)
			{
				return;
			}

			selectedProject_.BeginEdit();
			var dlg = new ProjectWindow(selectedProject_)
			{
				Owner = window_
			};

			bool? result = dlg.ShowDialog();
			if (result.HasValue && result.Value)
			{
				selectedProject_.EndEdit();
			}
			else
			{
				selectedProject_.CancelEdit();
			}
		}

		private void OnOptions()
		{
			(new OptionsWindow()
			{
				Owner = window_
			}).ShowDialog();
		}
		#endregion
	}
}
